home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Capture / PlayCap / playcap.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  14.0 KB  |  514 lines

  1. //------------------------------------------------------------------------------
  2. // File: PlayCap.cpp
  3. //
  4. // Desc: DirectShow sample code - a very basic application using Capture
  5. //       Devices.  It creates a window and uses the first available Capture
  6. //       Device to render and preview video capture data.
  7. //
  8. // Copyright (c) 1999-2001 Microsoft Corporation.  All rights reserved.
  9. //------------------------------------------------------------------------------
  10.  
  11.  
  12. #include <atlbase.h>
  13. #include <windows.h>
  14. #include <dshow.h>
  15. #include <stdio.h>
  16.  
  17. #include "playcap.h"
  18.  
  19. // An application can advertise the existence of its filter graph
  20. // by registering the graph with a global Running Object Table (ROT).
  21. // The GraphEdit application can detect and remotely view the running
  22. // filter graph, allowing you to 'spy' on the graph with GraphEdit.
  23. //
  24. // To enable registration in this sample, define REGISTER_FILTERGRAPH.
  25. //
  26. #define REGISTER_FILTERGRAPH
  27.  
  28.  
  29. //
  30. // Global data
  31. //
  32. HWND ghApp=0;
  33. DWORD g_dwGraphRegister=0;
  34.  
  35. IVideoWindow  * g_pVW = NULL;
  36. IMediaControl * g_pMC = NULL;
  37. IMediaEventEx * g_pME = NULL;
  38. IGraphBuilder * g_pGraph = NULL;
  39. ICaptureGraphBuilder2 * g_pCapture = NULL;
  40. PLAYSTATE g_psCurrent = Stopped;
  41.  
  42.  
  43. HRESULT CaptureVideo()
  44. {
  45.     HRESULT hr;
  46.     IBaseFilter *pSrcFilter=NULL;
  47.  
  48.     // Get DirectShow interfaces
  49.     hr = GetInterfaces();
  50.     if (FAILED(hr))
  51.     {
  52.         Msg(TEXT("Failed to get video interfaces!  hr=0x%x"), hr);
  53.         return hr;
  54.     }
  55.  
  56.     // Attach the filter graph to the capture graph
  57.     hr = g_pCapture->SetFiltergraph(g_pGraph);
  58.     if (FAILED(hr))
  59.     {
  60.         Msg(TEXT("Failed to set capture filter graph!  hr=0x%x"), hr);
  61.         return hr;
  62.     }
  63.  
  64.     // Use the system device enumerator and class enumerator to find
  65.     // a video capture/preview device, such as a desktop USB video camera.
  66.     hr = FindCaptureDevice(&pSrcFilter);
  67.     if (FAILED(hr))
  68.     {
  69.         // Don't display a message because FindCaptureDevice will handle it
  70.         return hr;
  71.     }
  72.    
  73.     // Add Capture filter to our graph.
  74.     hr = g_pGraph->AddFilter(pSrcFilter, L"Video Capture");
  75.     if (FAILED(hr))
  76.     {
  77.         Msg(TEXT("Couldn't add capture filter to graph!  hr=0x%x"), hr);
  78.         pSrcFilter->Release();
  79.         return hr;
  80.     }
  81.  
  82.     // Render the preview pin on the video capture filter
  83.     // Use this instead of g_pGraph->RenderFile
  84.     hr = g_pCapture->RenderStream (&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
  85.                                  pSrcFilter, NULL, NULL);
  86.     if (FAILED(hr))
  87.     {
  88.         Msg(TEXT("Couldn't render capture stream.  ")
  89.             TEXT("The device may already be in use.\r\n\r\nhr=0x%x"), hr);
  90.         pSrcFilter->Release();
  91.         return hr;
  92.     }
  93.  
  94.     // Now that the filter has been added to the graph and we have
  95.     // rendered its stream, we can release this reference to the filter.
  96.     pSrcFilter->Release();
  97.  
  98.     // Set video window style and position
  99.     hr = SetupVideoWindow();
  100.     if (FAILED(hr))
  101.     {
  102.         Msg(TEXT("Couldn't initialize video window!  hr=0x%x"), hr);
  103.         return hr;
  104.     }
  105.  
  106.     // Add our graph to the running object table, which will allow
  107.     // the GraphEdit application to "spy" on our graph
  108. #ifdef REGISTER_FILTERGRAPH
  109.     hr = AddGraphToRot(g_pGraph, &g_dwGraphRegister);
  110.     if (FAILED(hr))
  111.     {
  112.         Msg(TEXT("Failed to register filter graph with ROT!  hr=0x%x"), hr);
  113.         g_dwGraphRegister = 0;
  114.     }
  115. #endif
  116.  
  117.     // Start previewing video data
  118.     hr = g_pMC->Run();
  119.     if (FAILED(hr))
  120.     {
  121.         Msg(TEXT("Couldn't run the graph!  hr=0x%x"), hr);
  122.         return hr;
  123.     }
  124.  
  125.     // Remember current state
  126.     g_psCurrent = Running;
  127.         
  128.     return S_OK;
  129. }
  130.  
  131.  
  132. HRESULT FindCaptureDevice(IBaseFilter ** ppSrcFilter)
  133. {
  134.     HRESULT hr;
  135.     IBaseFilter * pSrc = NULL;
  136.     CComPtr <IMoniker> pMoniker =NULL;
  137.     ULONG cFetched;
  138.    
  139.     // Create the system device enumerator
  140.     CComPtr <ICreateDevEnum> pDevEnum =NULL;
  141.  
  142.     hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
  143.         IID_ICreateDevEnum, (void ** ) &pDevEnum);
  144.     if (FAILED(hr))
  145.     {
  146.         Msg(TEXT("Couldn't create system enumerator!  hr=0x%x"), hr);
  147.         return hr;
  148.     }
  149.  
  150.     // Create an enumerator for the video capture devices
  151.     CComPtr <IEnumMoniker> pClassEnum = NULL;
  152.  
  153.     hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
  154.     if (FAILED(hr))
  155.     {
  156.         Msg(TEXT("Couldn't create class enumerator!  hr=0x%x"), hr);
  157.         return hr;
  158.     }
  159.  
  160.     // If there are no enumerators for the requested type, then 
  161.     // CreateClassEnumerator will succeed, but pClassEnum will be NULL.
  162.     if (pClassEnum == NULL)
  163.     {
  164.         MessageBox(ghApp,TEXT("No video capture device was detected.\r\n\r\n")
  165.                    TEXT("This sample requires a video capture device, such as a USB WebCam,\r\n")
  166.                    TEXT("to be installed and working properly.  The sample will now close."),
  167.                    TEXT("No Video Capture Hardware"), MB_OK | MB_ICONINFORMATION);
  168.         return E_FAIL;
  169.     }
  170.  
  171.     // Use the first video capture device on the device list.
  172.     // Note that if the Next() call succeeds but there are no monikers,
  173.     // it will return S_FALSE (which is not a failure).  Therefore, we
  174.     // check that the return code is S_OK instead of using SUCCEEDED() macro.
  175.     if (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))
  176.     {
  177.         // Bind Moniker to a filter object
  178.         hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pSrc);
  179.         if (FAILED(hr))
  180.         {
  181.             Msg(TEXT("Couldn't bind moniker to filter object!  hr=0x%x"), hr);
  182.             return hr;
  183.         }
  184.     }
  185.     else
  186.     {
  187.         Msg(TEXT("Unable to access video capture device!"));   
  188.         return E_FAIL;
  189.     }
  190.  
  191.     // Copy the found filter pointer to the output parameter.
  192.     // Do NOT Release() the reference, since it will still be used
  193.     // by the calling function.
  194.     *ppSrcFilter = pSrc;
  195.  
  196.     return hr;
  197. }
  198.  
  199.  
  200. HRESULT GetInterfaces(void)
  201. {
  202.     HRESULT hr;
  203.  
  204.     // Create the filter graph
  205.     hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,
  206.         IID_IGraphBuilder, (void **) &g_pGraph);
  207.     if (FAILED(hr))
  208.         return hr;
  209.  
  210.     // Create the capture graph builder
  211.     hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
  212.         IID_ICaptureGraphBuilder2, (void **) &g_pCapture);
  213.     if (FAILED(hr))
  214.         return hr;
  215.     
  216.     // Obtain interfaces for media control and Video Window
  217.     hr = g_pGraph->QueryInterface(IID_IMediaControl,(LPVOID *) &g_pMC);
  218.     if (FAILED(hr))
  219.         return hr;
  220.  
  221.     hr = g_pGraph->QueryInterface(IID_IVideoWindow, (LPVOID *) &g_pVW);
  222.     if (FAILED(hr))
  223.         return hr;
  224.  
  225.     hr = g_pGraph->QueryInterface(IID_IMediaEvent, (LPVOID *) &g_pME);
  226.     if (FAILED(hr))
  227.         return hr;
  228.  
  229.     // Set the window handle used to process graph events
  230.     hr = g_pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0);
  231.  
  232.     return hr;
  233. }
  234.  
  235.  
  236. void CloseInterfaces(void)
  237. {
  238.     // Stop previewing data
  239.     if (g_pMC)
  240.         g_pMC->StopWhenReady();
  241.  
  242.     g_psCurrent = Stopped;
  243.  
  244.     // Stop receiving events
  245.     if (g_pME)
  246.         g_pME->SetNotifyWindow(NULL, WM_GRAPHNOTIFY, 0);
  247.  
  248.     // Relinquish ownership (IMPORTANT!) of the video window.
  249.     // Failing to call put_Owner can lead to assert failures within
  250.     // the video renderer, as it still assumes that it has a valid
  251.     // parent window.
  252.     if(g_pVW)
  253.     {
  254.         g_pVW->put_Visible(OAFALSE);
  255.         g_pVW->put_Owner(NULL);
  256.     }
  257.  
  258. #ifdef REGISTER_FILTERGRAPH
  259.     // Remove filter graph from the running object table   
  260.     if (g_dwGraphRegister)
  261.         RemoveGraphFromRot(g_dwGraphRegister);
  262. #endif
  263.  
  264.     // Release DirectShow interfaces
  265.     SAFE_RELEASE(g_pMC);
  266.     SAFE_RELEASE(g_pME);
  267.     SAFE_RELEASE(g_pVW);
  268.     SAFE_RELEASE(g_pGraph);
  269.     SAFE_RELEASE(g_pCapture);
  270. }
  271.  
  272.  
  273. HRESULT SetupVideoWindow(void)
  274. {
  275.     HRESULT hr;
  276.  
  277.     // Set the video window to be a child of the main window
  278.     hr = g_pVW->put_Owner((OAHWND)ghApp);
  279.     if (FAILED(hr))
  280.         return hr;
  281.     
  282.     // Set video window style
  283.     hr = g_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);
  284.     if (FAILED(hr))
  285.         return hr;
  286.  
  287.     // Use helper function to position video window in client rect 
  288.     // of main application window
  289.     ResizeVideoWindow();
  290.  
  291.     // Make the video window visible, now that it is properly positioned
  292.     hr = g_pVW->put_Visible(OATRUE);
  293.     if (FAILED(hr))
  294.         return hr;
  295.  
  296.     return hr;
  297. }
  298.  
  299.  
  300. void ResizeVideoWindow(void)
  301. {
  302.     RECT rc;
  303.  
  304.     // Make the preview video fill our window
  305.     GetClientRect(ghApp, &rc);
  306.  
  307.     // Resize the video preview window to match owner window size
  308.     if (g_pVW)
  309.         g_pVW->SetWindowPosition(0, 0, rc.right, rc.bottom);
  310. }
  311.  
  312.  
  313. HRESULT ChangePreviewState(int nShow)
  314. {
  315.     HRESULT hr=S_OK;
  316.     
  317.     // If the media control interface isn't ready, don't call it
  318.     if (!g_pMC)
  319.         return S_OK;
  320.     
  321.     if (nShow)
  322.     {
  323.         if (g_psCurrent != Running)
  324.         {
  325.             // Start previewing video data
  326.             hr = g_pMC->Run();
  327.             g_psCurrent = Running;
  328.         }
  329.     }
  330.     else
  331.     {
  332.         // Stop previewing video data
  333.         hr = g_pMC->StopWhenReady();
  334.         g_psCurrent = Stopped;
  335.     }
  336.  
  337.     return hr;
  338. }
  339.  
  340.  
  341. #ifdef REGISTER_FILTERGRAPH
  342.  
  343. HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister) 
  344. {
  345.     IMoniker * pMoniker;
  346.     IRunningObjectTable *pROT;
  347.     WCHAR wsz[128];
  348.     HRESULT hr;
  349.  
  350.     if (FAILED(GetRunningObjectTable(0, &pROT))) {
  351.         return E_FAIL;
  352.     }
  353.  
  354.     wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, 
  355.               GetCurrentProcessId());
  356.  
  357.     hr = CreateItemMoniker(L"!", wsz, &pMoniker);
  358.     if (SUCCEEDED(hr)) {
  359.         hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister);
  360.         pMoniker->Release();
  361.     }
  362.     pROT->Release();
  363.     return hr;
  364. }
  365.  
  366.  
  367. void RemoveGraphFromRot(DWORD pdwRegister)
  368. {
  369.     IRunningObjectTable *pROT;
  370.  
  371.     if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
  372.         pROT->Revoke(pdwRegister);
  373.         pROT->Release();
  374.     }
  375. }
  376.  
  377. #endif
  378.  
  379.  
  380. void Msg(TCHAR *szFormat, ...)
  381. {
  382.     TCHAR szBuffer[512];
  383.  
  384.     va_list pArgs;
  385.     va_start(pArgs, szFormat);
  386.     _vstprintf(szBuffer, szFormat, pArgs);
  387.     va_end(pArgs);
  388.  
  389.     MessageBox(NULL, szBuffer, TEXT("PlayCap Message"), MB_OK | MB_ICONERROR);
  390. }
  391.  
  392.  
  393. HRESULT HandleGraphEvent(void)
  394. {
  395.     LONG evCode, evParam1, evParam2;
  396.     HRESULT hr=S_OK;
  397.  
  398.     while(SUCCEEDED(g_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1, 
  399.                    (LONG_PTR *) &evParam2, 0)))
  400.     {
  401.         //
  402.         // Free event parameters to prevent memory leaks associated with
  403.         // event parameter data.  While this application is not interested
  404.         // in the received events, applications should always process them.
  405.         //
  406.         hr = g_pME->FreeEventParams(evCode, evParam1, evParam2);
  407.         
  408.         // Insert event processing code here, if desired
  409.     }
  410.  
  411.     return hr;
  412. }
  413.  
  414.  
  415. LRESULT CALLBACK WndMainProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  416. {
  417.     switch (message)
  418.     {
  419.         case WM_GRAPHNOTIFY:
  420.             HandleGraphEvent();
  421.             break;
  422.  
  423.         case WM_SIZE:
  424.             ResizeVideoWindow();
  425.             break;
  426.  
  427.         case WM_WINDOWPOSCHANGED:
  428.             ChangePreviewState(! (IsIconic(hwnd)));
  429.             break;
  430.  
  431.         case WM_CLOSE:            
  432.             // Hide the main window while the graph is destroyed
  433.             ShowWindow(ghApp, SW_HIDE);
  434.             CloseInterfaces();  // Stop capturing and release interfaces
  435.             break;
  436.  
  437.         case WM_DESTROY:
  438.             PostQuitMessage(0);
  439.             return 0;
  440.     }
  441.     return DefWindowProc (hwnd , message, wParam, lParam);
  442. }
  443.  
  444.  
  445. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hInstP, LPSTR lpCmdLine, int nCmdShow)
  446. {
  447.     MSG msg={0};
  448.     WNDCLASS wc;
  449.  
  450.     // Initialize COM
  451.     if(FAILED(CoInitialize(NULL)))
  452.     {
  453.         Msg(TEXT("CoInitialize Failed!\r\n"));   
  454.         exit(1);
  455.     } 
  456.  
  457.     // Register the window class
  458.     ZeroMemory(&wc, sizeof wc);
  459.     wc.lpfnWndProc   = WndMainProc;
  460.     wc.hInstance     = hInstance;
  461.     wc.lpszClassName = CLASSNAME;
  462.     wc.lpszMenuName  = NULL;
  463.     wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  464.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  465.     wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_VIDPREVIEW));
  466.     if(!RegisterClass(&wc))
  467.     {
  468.         Msg(TEXT("RegisterClass Failed! Error=0x%x\r\n"), GetLastError());
  469.         CoUninitialize();
  470.         exit(1);
  471.     }
  472.  
  473.     // Create the main window.  The WS_CLIPCHILDREN style is required.
  474.     ghApp = CreateWindow(CLASSNAME, APPLICATIONNAME,
  475.                     WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_CLIPCHILDREN,
  476.                     CW_USEDEFAULT, CW_USEDEFAULT,
  477.                     DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT,
  478.                     0, 0, hInstance, 0);
  479.  
  480.     if(ghApp)
  481.     {
  482.         HRESULT hr;
  483.  
  484.         // Create DirectShow graph and start capturing video
  485.         hr = CaptureVideo();
  486.         if (FAILED (hr))
  487.         {
  488.             CloseInterfaces();
  489.             DestroyWindow(ghApp);
  490.         }
  491.         else
  492.         {
  493.             // Don't display the main window until the DirectShow
  494.             // preview graph has been created.  Once video data is
  495.             // being received and processed, the window will appear
  496.             // and immediately have useful video data to dispay.
  497.             // Otherwise, it will be black until video data arrives.
  498.             ShowWindow(ghApp, nCmdShow);
  499.         }       
  500.  
  501.         // Main message loop
  502.         while(GetMessage(&msg,NULL,0,0))
  503.         {
  504.             TranslateMessage(&msg);
  505.             DispatchMessage(&msg);
  506.         }
  507.     }
  508.  
  509.     // Release COM
  510.     CoUninitialize();
  511.  
  512.     return (int) msg.wParam;
  513. }
  514.